package com.carrot.uaa.app;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.carrot.common.core.domain.R;
import com.carrot.uaa.common.exception.AuthResponseErrorEnum;
import com.carrot.uaa.constant.BusinessCodeConstants;
import com.carrot.uaa.constant.SecurityConstants;
import com.carrot.uaa.domain.IAuthBusinessRuleService;
import com.carrot.uaa.entity.OAuth2User;
import com.carrot.uaa.entity.dto.SmsCaptchaDTO;
import com.carrot.uaa.entity.dto.SmsModelDTO;
import com.carrot.uaa.enums.SmsTypeEnum;
import com.carrot.uaa.infrastructure.kafka.ISmsProducer;
import com.carrot.uaa.infrastructure.mapper.AuthorizationMapper;
import com.carrot.uaa.infrastructure.redis.RedisOperator;
import com.carrot.uaa.infrastructure.service.UserService;
import com.carrot.uaa.property.UaaAuthLoginProperties;
import com.carrot.uaa.util.DateUtils;
import com.carrot.uaa.util.RedisUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.carrot.uaa.util.ParamCheckUtils;

/**
 * 登录业务
 */
@Service
@RequiredArgsConstructor
public class LoginAppServiceImpl implements LoginAppService {

    private final RedisOperator<Object> redisOperator;

    private final UserService userService;

    private final UaaAuthLoginProperties uaaAuthLoginProperties;

    private final ISmsProducer iSmsProducer;

    private final IAuthBusinessRuleService iAuthBusinessRuleService;

    private final AuthorizationMapper authorizationMapper;

    @Override
    public Boolean out(HttpServletRequest request) {
        //清除redis中的令牌
        String accessToken = request.getParameter("accessToken");
        if(StrUtil.isEmpty(accessToken)){
            return false;
        }
        String accessTokenKey = RedisUtils.getUserOnLineAccessTokenKey(accessToken);
        //删除访问令牌
        redisOperator.delete(accessTokenKey);
        return true;
    }

    @Override
    public R<?> getSmsCaptcha(SmsCaptchaDTO smsCaptchaDTO) {

        String phone = smsCaptchaDTO.getPhone();
        String appName = smsCaptchaDTO.getAppName();
        //校验手机号格式
        if(!ParamCheckUtils.phoneCheck(phone)){
            return R.fail(AuthResponseErrorEnum.AUTH_PHONE_FORMAT_ERROR);
        }
        //校验账户
        OAuth2User OAuth2User = userService.getUserByAccount(phone);
        if(OAuth2User==null){
            return R.fail(AuthResponseErrorEnum.AUTH_PHONE_UNREGISTERED);
        }
        try{
            iAuthBusinessRuleService.checkAccount(OAuth2User);
        }catch (Exception e){
            return R.fail(BusinessCodeConstants.BUSINESS_CHECK_NO_PASS,e.getMessage());
        }
        //校验短信发送次数
        if(!smsCodeCheck(phone)){
            return R.fail(AuthResponseErrorEnum.AUTH_SMS_CAPTCHA_THRESHOLD_LIMIT);
        }
        //发送短信验证码
        String smsCaptcha = sendCaptchaByPhone(phone);
        //缓存短信验证码
        redisOperator.set(RedisUtils.getLoginSmsCaptchaKey(phone,appName), smsCaptcha, SecurityConstants.DEFAULT_TIMEOUT_SECONDS);
        //增加短信发送次数
        addSendCaptchaCountByPhone(phone);

        return R.ok("验证码已发送，请注意查收");
    }

    /**
     * 验证码校验，通过 true 未通过 false
     * @param phone
     * @return
     */
    private boolean smsCodeCheck(String phone){
        //校验次数是否超过阀值
        Object count = redisOperator.get(RedisUtils.getLoginSmsCaptchaCountKey(phone));
        if(count == null||Integer.parseInt(count.toString()) <=uaaAuthLoginProperties.getSendSmsCodeThreshold()){
            return true;
        }
        return false;
    }

    /**
     * 根据手机号发送短信
     * @param phone
     * @return
     */
    private String sendCaptchaByPhone(String phone){
        //生成短信验证码
        String captcha = RandomUtil.randomNumbers(4);
        //发送短信
        SmsModelDTO smsModelDto = new SmsModelDTO();
        smsModelDto.setTels(Collections.singletonList(phone));
        smsModelDto.setSmsTypeEnum(SmsTypeEnum.LOGIN_CAPTCHA);
        Map<String, String> param = new HashMap<>(1);
        param.put("code", captcha);
        smsModelDto.setTemplateParam(param);
        iSmsProducer.sendCaptcha(smsModelDto);

        return captcha;
    }

    /**
     * 根据手机号增加用户当天的发送验证码次数
     * @param phone
     */
    private void addSendCaptchaCountByPhone(String phone){
        String key = RedisUtils.getLoginSmsCaptchaCountKey(phone);
        Long count = redisOperator.incr(key);
        if(count == 1){
            //初始化过期时间
            redisOperator.expire(key, DateUtils.remainingTimeByDay(DateUnit.MINUTE), TimeUnit.MINUTES);
        }
    }


}
